package dto

import (
	"time"
	"wxpay/internal/model"
	"wxpay/pkg/util"
)

type SettleInfo struct {
	// 是否指定分账
	ProfitSharing bool
	// 补差金额
	SubsidyAmount int
}

type AmountInfo struct {
	// 总金额
	Total uint
	// 货币类型
	Currency string
}

type PayerInfo struct {
	// 用户服务标识
	SpOpenID string
	// 用户子标识
	SubOpenID string
}

// 场景信息
type SceneInfo struct {
	// 用户终端IP
	PayerClientIP string
	// 商户端设备号
	DeviceID string
	// 商户门店信息
	StoreInfo struct {
		// 门店编号
		ID string
		// 门店名称
		Name string
		// 地区编码
		AreaCode string
		// 详细地址
		Address string
	}
}

// 交易DTO
type TradeDTO struct {
	ID int64
	// 品牌id
	BrandID string
	// 商户号
	MchID string
	// 二级商户号
	SubMchID string
	// 服务商app_id
	AppID string
	// 二级商户app_id
	SubAppID string
	// 商户订单号
	OutTradeNo string
	// 交易结束时间
	ExpireTime time.Time
	// 结算信息
	SettleInfo *SettleInfo
	// 订单金额
	AmountInfo AmountInfo
	// 支付者
	PayerInfo *PayerInfo
	// 商品描述
	Description string
	// 场景信息
	SceneInfo *SceneInfo
	// 预支付交易标识
	PrepayID string
	// 微信支付单号
	WxTransID string
	// 交易类型
	TradeType string
	// 交易状态
	TradeState string
	// 交易状态描述
	TradeStateDesc string
	// 交易成功实践
	SuccessTime *time.Time
	// 创建时间
	CreateTime time.Time
	// 修改时间
	UpdateTime time.Time
	// 服务费率
	serviceRate int64
	// 服务费
	serviceFee int64
}

// 填充服务费率
func (t *TradeDTO) SetServiceRate(rate int64) {
	t.serviceRate = rate
}

func (t *TradeDTO) GetServiceRate() int64 {
	return t.serviceRate
}

func (t *TradeDTO) SetServiceFee(fee int64) {
	t.serviceFee = fee
}

func (t *TradeDTO) GetServiceFee() int64 {
	return t.serviceFee
}

// JSAPI调起支付结构
type PrepayDTO struct {
	// 服务商app_id
	AppID string
	// 时间戳
	TimeStamp string
	// 随机字符串
	Nonce string
	// prepay_id
	Package string
	// 签名类型
	SignType string
	// 签名
	PaySign string
	// 交易过期时间
	ExpireTime time.Time
}

// dto to model
func AdaptTrade(info TradeDTO) (r *model.Trade) {
	r = &model.Trade{
		ID:             info.ID,
		BrandID:        info.BrandID,
		MchID:          info.MchID,
		SubMchID:       info.SubMchID,
		AppID:          info.AppID,
		SubAppID:       util.AdaptNullString(info.SubAppID),
		OutTradeNo:     info.OutTradeNo,
		ExpireTime:     info.ExpireTime,
		SettleInfo:     adaptSettleInfo(info.SettleInfo).ToJson(),
		AmountInfo:     adaptAmountInfo(info.AmountInfo).ToJson(),
		PayerInfo:      adaptPayerInfo(info.PayerInfo).ToJson(),
		SceneInfo:      adaptSceneInfo(info.SceneInfo).ToJson(),
		Description:    info.Description,
		Extra:          model.NewTradeExtra(info.serviceRate).ToJson(),
		PrepayID:       util.AdaptNullString(info.PrepayID),
		WxTransID:      util.AdaptNullString(info.WxTransID),
		TradeType:      util.AdaptNullString(info.TradeType),
		TradeState:     util.AdaptNullString(info.TradeState),
		TradeStateDesc: util.AdaptNullString(info.TradeStateDesc),
		SuccessTime:    info.SuccessTime,
		CreateTime:     info.CreateTime,
		UpdateTime:     info.UpdateTime,
	}
	return
}

func adaptSettleInfo(info *SettleInfo) (r *model.SettleInfo) {
	if info == nil {
		return
	}
	r = &model.SettleInfo{
		ProfitSharing: info.ProfitSharing,
		SubsidyAmount: info.SubsidyAmount,
	}
	return
}

func adaptAmountInfo(info AmountInfo) (r *model.AmountInfo) {
	r = &model.AmountInfo{
		Total:    info.Total,
		Currency: info.Currency,
	}
	return
}

func adaptPayerInfo(info *PayerInfo) (r *model.Payer) {
	if info == nil {
		return
	}
	r = &model.Payer{
		SpOpenID:  info.SpOpenID,
		SubOpenID: info.SubOpenID,
	}
	return
}

func adaptSceneInfo(info *SceneInfo) (r *model.SceneInfo) {
	if info == nil {
		return
	}
	r = &model.SceneInfo{
		PayerClientIP: info.PayerClientIP,
		DeviceID:      info.DeviceID,
		StoreInfo: struct {
			ID       string `json:"id"`
			Name     string `json:"name"`
			AreaCode string `json:"area_code"`
			Address  string `json:"address"`
		}{
			ID:       info.StoreInfo.ID,
			Name:     info.StoreInfo.Name,
			AreaCode: info.StoreInfo.AreaCode,
			Address:  info.StoreInfo.Address,
		},
	}
	return
}

// model to dto
func ConvertTrade(trade *model.Trade) *TradeDTO {
	settle := &model.SettleInfo{}
	settle.ToStruct(trade.SettleInfo)
	amount := &model.AmountInfo{}
	amount.ToStruct(trade.AmountInfo)
	payer := &model.Payer{}
	payer.ToStruct(trade.PayerInfo)
	t := &TradeDTO{
		ID:         trade.ID,
		BrandID:    trade.BrandID,
		MchID:      trade.MchID,
		SubMchID:   trade.SubMchID,
		AppID:      trade.AppID,
		SubAppID:   util.ConvertNullString(trade.SubAppID),
		OutTradeNo: trade.OutTradeNo,
		ExpireTime: trade.ExpireTime,
		SettleInfo: &SettleInfo{
			ProfitSharing: settle.ProfitSharing,
			SubsidyAmount: settle.SubsidyAmount,
		},
		AmountInfo: AmountInfo{
			Total:    amount.Total,
			Currency: amount.Currency,
		},
		PayerInfo: &PayerInfo{
			SpOpenID:  payer.SpOpenID,
			SubOpenID: payer.SubOpenID,
		},
		Description:    trade.Description,
		SceneInfo:      nil,
		PrepayID:       util.ConvertNullString(trade.PrepayID),
		WxTransID:      util.ConvertNullString(trade.WxTransID),
		TradeType:      util.ConvertNullString(trade.TradeType),
		TradeState:     util.ConvertNullString(trade.TradeState),
		TradeStateDesc: util.ConvertNullString(trade.TradeStateDesc),
		SuccessTime:    trade.SuccessTime,
		CreateTime:     trade.CreateTime,
		UpdateTime:     trade.UpdateTime,
	}
	t.SetServiceRate(trade.GetServiceRate())
	fee := trade.GetServiceFee()
	if fee != nil {
		t.SetServiceFee(*fee)
	}
	return t
}

// 支付成功通知参数
type PayNotificationDTO struct {
	// 服务商公众号ID
	SpAppID string `json:"sp_appid"`
	// 服务商户号
	SpMchID string `json:"sp_mchid"`
	// 二级商户公众号ID
	SubAppID string `json:"sub_appid"`
	// 二级商户号
	SubMchID string `json:"sub_mchid"`
	// 商户订单号
	OutTradeNo string `json:"out_trade_no"`
	// 微信支付订单号
	TransactionID string `json:"transaction_id"`
	// 交易类型
	TradeType string `json:"trade_type"`
	// 交易状态
	TradeState string `json:"trade_state"`
	// 交易状态描述
	TradeStateDesc string `json:"trade_state_desc"`
	// 付款银行
	BankType string `json:"bank_type"`
	// 附加数据
	Attach string `json:"attach"`
	// 支付完成时间
	SuccessTime string `json:"success_time"`
}
